using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Volo.Abp.Domain.Repositories;
using Volo.Abp.EventBus.Distributed;
using Volo.Abp.Uow;
using Matrix.ServiceDiscovery.Dtos;
using Matrix.ServiceDiscovery.Entities;
using Matrix.ServiceDiscovery.Enums;
using Matrix.ServiceDiscovery.Events;

namespace Matrix.ServiceDiscovery.Services
{
    /// <summary>
    /// 服务发现命令服务
    /// 专注业务逻辑和事务一致性
    /// </summary>
    public class ServiceDiscoveryCommandService : ApplicationService
    {
        private readonly IServiceInfoRepository _serviceRepository;
        private readonly IDistributedEventBus _eventBus;
        private readonly ILogger<ServiceDiscoveryCommandService> _logger;

        public ServiceDiscoveryCommandService(
            IServiceInfoRepository serviceRepository,
            IDistributedEventBus eventBus,
            ILogger<ServiceDiscoveryCommandService> logger)
        {
            _serviceRepository = serviceRepository;
            _eventBus = eventBus;
            _logger = logger;
        }

        /// <summary>
        /// 创建服务
        /// </summary>
        [UnitOfWork]
        public async Task<ServiceInfoDto> CreateAsync(CreateServiceInfoDto input)
        {
            // 业务规则验证
            await ValidateCreateBusinessRulesAsync(input);

            var service = new ServiceInfo(
                GuidGenerator.Create(),
                input.Name,
                input.Version,
                input.ServiceType,
                input.Description,
                input.ServiceGroup
            );

            await _serviceRepository.InsertAsync(service);

            // 发布领域事件
            await PublishServiceChangedEventAsync(new ServiceChangedEto
            {
                EventType = "Create",
                ServiceId = service.Id,
                ServiceName = service.Name,
                ServiceType = service.ServiceType.ToString(),
                NewValue = service.Name,
                ChangedBy = CurrentUser.Name ?? "System"
            });

            _logger.LogInformation("创建服务成功: {ServiceName} ({ServiceId})", service.Name, service.Id);

            return ObjectMapper.Map<ServiceInfo, ServiceInfoDto>(service);
        }

        /// <summary>
        /// 更新服务信息
        /// </summary>
        [UnitOfWork]
        public async Task<ServiceInfoDto> UpdateAsync(Guid id, UpdateServiceInfoDto input)
        {
            var service = await _serviceRepository.GetAsync(id);
            var oldName = service.Name;
            var oldDescription = service.Description;
            var oldServiceGroup = service.ServiceGroup;

            // 更新基本信息
            if (!string.IsNullOrWhiteSpace(input.Name) && input.Name != oldName)
            {
                service.SetName(input.Name);
            }

            if (!string.IsNullOrWhiteSpace(input.Description) && input.Description != oldDescription)
            {
                service.SetDescription(input.Description);
            }

            if (!string.IsNullOrWhiteSpace(input.ServiceGroup) && input.ServiceGroup != oldServiceGroup)
            {
                service.SetServiceGroup(input.ServiceGroup);
            }

            if (input.Version != null && input.Version != service.Version)
            {
                service.SetVersion(input.Version);
            }

            await _serviceRepository.UpdateAsync(service);

            // 发布更新事件
            await PublishServiceChangedEventAsync(new ServiceChangedEto
            {
                EventType = "Update",
                ServiceId = service.Id,
                ServiceName = service.Name,
                ServiceType = service.ServiceType.ToString(),
                OldValue = $"{oldName}|{oldDescription}|{oldServiceGroup}",
                NewValue = $"{service.Name}|{service.Description}|{service.ServiceGroup}",
                ChangedBy = CurrentUser.Name ?? "System"
            });

            _logger.LogInformation("更新服务成功: {ServiceName} ({ServiceId})", service.Name, service.Id);

            return ObjectMapper.Map<ServiceInfo, ServiceInfoDto>(service);
        }

        /// <summary>
        /// 删除服务
        /// </summary>
        [UnitOfWork]
        public async Task DeleteAsync(Guid id)
        {
            var service = await _serviceRepository.GetAsync(id);

            await _serviceRepository.DeleteAsync(id);

            // 发布删除事件
            await PublishServiceChangedEventAsync(new ServiceChangedEto
            {
                EventType = "Delete",
                ServiceId = service.Id,
                ServiceName = service.Name,
                ServiceType = service.ServiceType.ToString(),
                OldValue = service.Name,
                ChangedBy = CurrentUser.Name ?? "System"
            });

            _logger.LogInformation("删除服务成功: {ServiceName} ({ServiceId})", service.Name, service.Id);
        }

        /// <summary>
        /// 注册服务实例
        /// </summary>
        [UnitOfWork]
        public async Task<ServiceInstanceDto> RegisterInstanceAsync(RegisterServiceInstanceDto input)
        {
            // 验证服务是否存在
            var service = await _serviceRepository.GetAsync(input.ServiceId);

            // 检查实例是否已存在
            var existingInstance = await _serviceRepository.GetInstanceByInstanceIdAsync(
                input.ServiceId, input.InstanceId);

            ServiceInstance instance;

            if (existingInstance != null)
            {
                // 更新现有实例
                existingInstance.UpdateFromRegistration(input);
                instance = existingInstance;
            }
            else
            {
                // 创建新实例
                instance = new ServiceInstance(
                    GuidGenerator.Create(),
                    input.ServiceId,
                    service.Name,
                    input.InstanceId,
                    input.Host,
                    input.Port,
                    input.Protocol,
                    input.Weight,
                    input.Region,
                    input.Zone
                );

                // 添加标签和元数据
                if (input.Tags?.Any() == true)
                {
                    foreach (var tag in input.Tags)
                    {
                        instance.AddTag(tag);
                    }
                }

                if (input.Metadata?.Any() == true)
                {
                    foreach (var metadata in input.Metadata)
                    {
                        instance.SetMetadata(metadata.Key, metadata.Value);
                    }
                }

                await _serviceRepository.InsertInstanceAsync(instance);
            }

            // 发布实例注册事件
            await PublishInstanceChangedEventAsync(new ServiceInstanceChangedEto
            {
                EventType = "Register",
                InstanceId = instance.Id,
                ServiceId = instance.ServiceId,
                ServiceName = instance.ServiceName,
                InstanceIdStr = instance.InstanceId,
                Address = $"{instance.Host}:{instance.Port}",
                HealthStatus = instance.HealthStatus.ToString(),
                ChangedBy = "System"
            });

            _logger.LogInformation("注册服务实例成功: {ServiceName}/{InstanceId} ({InstanceId})",
                service.Name, input.InstanceId, instance.Id);

            return ObjectMapper.Map<ServiceInstance, ServiceInstanceDto>(instance);
        }

        /// <summary>
        /// 注销服务实例
        /// </summary>
        [UnitOfWork]
        public async Task UnregisterInstanceAsync(Guid serviceId, string instanceId)
        {
            var instance = await _serviceRepository.GetInstanceByInstanceIdAsync(serviceId, instanceId);
            if (instance == null)
            {
                return; // 实例不存在，直接返回
            }

            await _serviceRepository.DeleteInstanceAsync(instance.Id);

            // 发布实例注销事件
            await PublishInstanceChangedEventAsync(new ServiceInstanceChangedEto
            {
                EventType = "Unregister",
                InstanceId = instance.Id,
                ServiceId = instance.ServiceId,
                ServiceName = instance.ServiceName,
                InstanceIdStr = instance.InstanceId,
                Address = $"{instance.Host}:{instance.Port}",
                HealthStatus = instance.HealthStatus.ToString(),
                ChangedBy = "System"
            });

            _logger.LogInformation("注销服务实例成功: {ServiceName}/{InstanceId} ({InstanceId})",
                instance.ServiceName, instanceId, instance.Id);
        }

        /// <summary>
        /// 更新实例健康状态
        /// </summary>
        [UnitOfWork]
        public async Task UpdateInstanceHealthStatusAsync(Guid instanceId, HealthStatus status)
        {
            var instance = await _serviceRepository.GetInstanceAsync(instanceId);
            if (instance == null)
            {
                return;
            }

            var oldStatus = instance.HealthStatus;
            instance.UpdateHealthStatus(status);

            await _serviceRepository.UpdateInstanceAsync(instance);

            // 发布健康状态变更事件
            await PublishInstanceChangedEventAsync(new ServiceInstanceChangedEto
            {
                EventType = "HealthStatusChanged",
                InstanceId = instance.Id,
                ServiceId = instance.ServiceId,
                ServiceName = instance.ServiceName,
                InstanceIdStr = instance.InstanceId,
                Address = $"{instance.Host}:{instance.Port}",
                OldValue = oldStatus.ToString(),
                NewValue = status.ToString(),
                HealthStatus = status.ToString(),
                ChangedBy = "System"
            });

            _logger.LogDebug("更新实例健康状态: {ServiceName}/{InstanceId} {OldStatus} -> {NewStatus}",
                instance.ServiceName, instance.InstanceId, oldStatus, status);
        }

        /// <summary>
        /// 记录实例心跳
        /// </summary>
        [UnitOfWork]
        public async Task RecordInstanceHeartbeatAsync(Guid instanceId)
        {
            var instance = await _serviceRepository.GetInstanceAsync(instanceId);
            if (instance == null)
            {
                return;
            }

            instance.RecordHeartbeat();
            await _serviceRepository.UpdateInstanceAsync(instance);

            _logger.LogTrace("记录实例心跳: {ServiceName}/{InstanceId}",
                instance.ServiceName, instance.InstanceId);
        }

        /// <summary>
        /// 更新负载均衡配置
        /// </summary>
        [UnitOfWork]
        public async Task<LoadBalancingConfigDto> UpdateLoadBalancingConfigAsync(
            Guid serviceId,
            UpdateLoadBalancingConfigDto input)
        {
            var service = await _serviceRepository.GetAsync(serviceId);
            var config = service.LoadBalancingConfig;

            var oldStrategy = config.Strategy;

            if (input.Strategy.HasValue)
            {
                config.UpdateStrategy(input.Strategy.Value);
            }

            if (input.EnableHealthCheck.HasValue ||
                input.HealthCheckInterval.HasValue ||
                input.FailureThreshold.HasValue ||
                input.SuccessThreshold.HasValue ||
                input.Timeout.HasValue)
            {
                config.UpdateHealthCheckSettings(
                    input.EnableHealthCheck ?? config.EnableHealthCheck,
                    input.HealthCheckInterval,
                    input.FailureThreshold,
                    input.SuccessThreshold,
                    input.Timeout);
            }

            await _serviceRepository.UpdateAsync(service);

            // 发布配置变更事件
            await PublishLoadBalancingConfigChangedEventAsync(new LoadBalancingConfigChangedEto
            {
                ServiceId = serviceId,
                ServiceName = service.Name,
                EventType = "Update",
                OldStrategy = oldStrategy.ToString(),
                NewStrategy = config.Strategy.ToString(),
                ChangedBy = CurrentUser.Name ?? "System"
            });

            _logger.LogInformation("更新负载均衡配置成功: {ServiceName} Strategy: {OldStrategy} -> {NewStrategy}",
                service.Name, oldStrategy, config.Strategy);

            return ObjectMapper.Map<LoadBalancingConfig, LoadBalancingConfigDto>(config);
        }

        /// <summary>
        /// 激活服务
        /// </summary>
        [UnitOfWork]
        public async Task<ServiceInfoDto> ActivateAsync(Guid id)
        {
            var service = await _serviceRepository.GetAsync(id);
            service.Activate();

            await _serviceRepository.UpdateAsync(service);

            await PublishServiceChangedEventAsync(new ServiceChangedEto
            {
                EventType = "Activate",
                ServiceId = service.Id,
                ServiceName = service.Name,
                ServiceType = service.ServiceType.ToString(),
                NewValue = service.Status.ToString(),
                ChangedBy = CurrentUser.Name ?? "System"
            });

            _logger.LogInformation("激活服务成功: {ServiceName} ({ServiceId})", service.Name, service.Id);

            return ObjectMapper.Map<ServiceInfo, ServiceInfoDto>(service);
        }

        /// <summary>
        /// 停用服务
        /// </summary>
        [UnitOfWork]
        public async Task<ServiceInfoDto> DeactivateAsync(Guid id)
        {
            var service = await _serviceRepository.GetAsync(id);
            service.Deactivate();

            await _serviceRepository.UpdateAsync(service);

            await PublishServiceChangedEventAsync(new ServiceChangedEto
            {
                EventType = "Deactivate",
                ServiceId = service.Id,
                ServiceName = service.Name,
                ServiceType = service.ServiceType.ToString(),
                NewValue = service.Status.ToString(),
                ChangedBy = CurrentUser.Name ?? "System"
            });

            _logger.LogInformation("停用服务成功: {ServiceName} ({ServiceId})", service.Name, service.Id);

            return ObjectMapper.Map<ServiceInfo, ServiceInfoDto>(service);
        }

        #region Private Methods

        private async Task ValidateCreateBusinessRulesAsync(CreateServiceInfoDto input)
        {
            // 检查服务名称是否已存在
            var existingService = await _serviceRepository.GetByNameAsync(input.Name);
            if (existingService != null)
            {
                throw new Volo.Abp.BusinessException("ServiceDiscovery:ServiceNameAlreadyExists")
                    .WithData("ServiceName", input.Name);
            }

            // 检查服务名称格式
            if (string.IsNullOrWhiteSpace(input.Name) || input.Name.Length > 100)
            {
                throw new Volo.Abp.BusinessException("ServiceDiscovery:InvalidServiceName");
            }

            // 检查版本格式
            if (string.IsNullOrWhiteSpace(input.Version) || input.Version.Length > 50)
            {
                throw new Volo.Abp.BusinessException("ServiceDiscovery:InvalidVersion");
            }
        }

        private async Task PublishServiceChangedEventAsync(ServiceChangedEto eventData)
        {
            try
            {
                await _eventBus.PublishAsync(eventData);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "发布服务变更事件失败: {ServiceId}", eventData.ServiceId);
            }
        }

        private async Task PublishInstanceChangedEventAsync(ServiceInstanceChangedEto eventData)
        {
            try
            {
                await _eventBus.PublishAsync(eventData);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "发布实例变更事件失败: {InstanceId}", eventData.InstanceId);
            }
        }

        private async Task PublishLoadBalancingConfigChangedEventAsync(LoadBalancingConfigChangedEto eventData)
        {
            try
            {
                await _eventBus.PublishAsync(eventData);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "发布负载均衡配置变更事件失败: {ServiceId}", eventData.ServiceId);
            }
        }

        #endregion
    }
}